package com.hmdp.utils;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.hmdp.entity.Shop;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

@Slf4j
@Component
public class CacheClient {

    @Resource
    StringRedisTemplate stringRedisTemplate;

    public void  set(String key, Object value,Long time,TimeUnit unit){
        stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(value),time+(int)(Math.random()*time), unit);
    }

    public  <R,ID> R queryWithPassThrough(String keyPrefix , ID id , Class<R> type, Function<ID,R> dbFallback, Long time,TimeUnit unit){

        String key = keyPrefix + id;

        String shopJson = stringRedisTemplate.opsForValue().get(key);

        if (StrUtil.isNotBlank(shopJson)) {
            //拿到字符，转为Shop.class，JSONUtil

            return JSONUtil.toBean(shopJson, type);
        }

        //剩下的就只有null和'',当命中''时,redis里面有这个键，是''，解决缓存穿透问题
        if(shopJson!=null){
            return null;
        }

        //redis里面都没有这个键，返回null，就要查数据库了,传一段函数，用户自己定义好数据库查询方式
        R r = dbFallback.apply(id);

        if (r == null) {
            stringRedisTemplate.opsForValue().set(key,"",2, TimeUnit.MINUTES);
            return null;
        }

        //将shop类转为字符存入redis,ttl后面添加随机时间解决线程雪崩
        this.set(key,r,time,unit);

        return r;

    }

}
